package com.coincalf.web;

import com.coincalf.chan.feign.MessagingServiceClient;
import com.coincalf.dto.*;
import com.coincalf.entity.Market;
import com.coincalf.framework.constants.Constant;
import com.coincalf.framework.enums.OrderType;
import com.coincalf.framework.enums.PriceType;
import com.coincalf.framework.exception.GlobalDefaultException;
import com.coincalf.framework.http.Response;
import com.coincalf.framework.security.UserDetails;
import com.coincalf.service.*;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.cert.ocsp.Req;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;

/**
 * @Description: 创新交易订单 controller
 * @Author: Chen Long
 * @Date: Created in 2018/5/15 下午12:14
 * @Modified by: Chen Long
 */
@RestController
@RequestMapping("/forex/order")
@Slf4j
@Api(value = "创新交易订单", description = "创新交易订单 REST API")
public class ForexOrderController implements Constant {

    @Autowired
    private EntrustOrderService entrustOrderService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ForexOpenPositionOrderService forexOpenPositionOrderService;
    @Autowired
    private ForexClosePositionOrderService forexClosePositionOrderService;
    @Autowired
    private TurnoverOrderService turnoverOrderService;
    @Autowired
    private MarketService marketService;
    @Autowired
    private MessagingServiceClient messagingServiceClient;
    @Autowired
    private ForexAccountService forexAccountService;
    @Autowired
    private CommonController commonController;


    /**
     * 创新交易委托下单
     *
     * @param order 创新交易委托下单请求参数
     * @return
     */
    //@PreAuthorize("isAuthenticated()")
    @PostMapping("/entrusts")
    @ApiOperation(value = "创新交易委托下单", notes = "创新交易委托下单", httpMethod = "POST")
    @ApiImplicitParam(name = "order", value = "创新交易委托下单请求参数", required = true, dataType = "CreateForexOrderDTO", paramType = "body")
    @ResponseBody
    public Object createEntrustOrder(
            HttpServletRequest request,
            @RequestBody CreateForexOrderDTO order
    ) {
        Long userId = commonController.getUserId(request);
        Market market = marketService.queryBySymbol(order.getSymbol());
        if (market == null) {
            log.error("交易市场错误");
            throw new GlobalDefaultException(50002);
        }
        // 委托价格
        if (order.getPriceType() == PriceType.LIMIT_PRICE.getCode()) {
            if (!Optional.ofNullable(order.getPrice()).isPresent()
                    || order.getPrice().compareTo(BigDecimal.ZERO) < 1) {
                log.error("委托价格错误");
                throw new GlobalDefaultException(50011);
            }
        }
        // 委托数量
        if (order.getVolume().compareTo(BigDecimal.ZERO) < 1) {
            log.error("委托数量错误");
            throw new GlobalDefaultException(50012);
        }
        // 委托数量
        if (order.getVolume().compareTo(new BigDecimal(order.getVolume().intValue())) != 0) {
            log.error("委托数量必须为整数");
            throw new GlobalDefaultException(50025);
        }
        // 买卖类型
        if (!Optional.ofNullable(OrderType.getByCode(order.getType())).isPresent()) {
            log.error("买卖类型错误");
            throw new GlobalDefaultException(50013);
        }
        // 价格类型
        if (!Optional.ofNullable(PriceType.getByCode(order.getPriceType())).isPresent()) {
            log.error("价格类型错误");
            throw new GlobalDefaultException(50014);
        }
        Response response = entrustOrderService.createForexOrder(market, order, userId);
        if (response.getData() == null) {
            return response;
        }
        long orderId = Long.valueOf(response.getData().toString());
        // 加入撮合队列
        String redisKey = new StringBuffer(REDIS_KEY_FOREX_MATCH).append(order.getSymbol()).toString();
        redisTemplate.opsForList().rightPush(redisKey, String.valueOf(orderId));
        // 更新行情数据
        marketService.FOREX_MARKET_CACHE_INSTANCE().refresh(market.getId());
        // 推送用户委托列表
        messagingServiceClient.convertAndSendToUser(Constant.CH_ENTRUST_ORDERS_UPDATE, String.valueOf(userId), "ok");
        // 推送用户持仓明细
        messagingServiceClient.convertAndSendToUser(Constant.CH_POSITION_DETAILS_UPDATE, String.valueOf(userId), "ok");
        // 推送用户持仓汇总
        messagingServiceClient.convertAndSendToUser(Constant.CH_POSITION_SUMMARY_UPDATE, String.valueOf(userId), "ok");
        return Response.ok();
    }

    /**
     * 撤销委托
     *
     * @param orderId 创新交易委托订单号
     * @return
     */
    //@PreAuthorize("isAuthenticated()")
    @DeleteMapping("/entrusts/{orderId}")
    @ApiOperation(value = "创新交易订单撤销委托", notes = "创新交易订单撤销委托", httpMethod = "DELETE")
    @ApiImplicitParam(name = "orderId", value = "创新交易委托订单号", required = true, dataType = "long", paramType = "path")
    @ResponseBody
    public Object cancelEntrustOrder(
            HttpServletRequest request,
            @PathVariable("orderId") long orderId
    ) {
        Long userId = commonController.getUserId(request);
        Market market = entrustOrderService.cancelForexOrder(orderId, userId);
        // 更新行情数据
        marketService.FOREX_MARKET_CACHE_INSTANCE().refresh(market.getId());
        // 推送用户委托列表
        messagingServiceClient.convertAndSendToUser(Constant.CH_ENTRUST_ORDERS_UPDATE, String.valueOf(userId), "ok");
        return Response.ok();
    }

    /**
     * 持仓明细
     *
     * @return
     */
    //@PreAuthorize("isAuthenticated()")
    @GetMapping("/holds")
    @ApiOperation(value = "持仓明细", httpMethod = "GET")
    @ResponseBody
    public Object positionDetails(HttpServletRequest request) {
        Long userId = commonController.getUserId(request);
        List<ForexOpenPositionOrderDTO> forexOpenPositionOrders = forexOpenPositionOrderService.selectHoldingsDetails(userId);
        return Response.ok(forexOpenPositionOrders);
    }

    /**
     * 持仓汇总
     *
     * @return
     */
    //@PreAuthorize("isAuthenticated()")
    @GetMapping("/gathers")
    @ApiOperation(value = "持仓汇总", httpMethod = "GET")
    @ResponseBody
    public Object positionSummary(HttpServletRequest request) {
        Long userId = commonController.getUserId(request);
        List<PositionSummaryDTO> positionSummary = forexAccountService.positionSummary(userId);
        return Response.ok(positionSummary);
    }

    /**
     * 今日平仓
     *
     * @return
     */
    @GetMapping("/today_closeout")
    @ApiOperation(value = "今⽇平仓", httpMethod = "GET")
    @ResponseBody
    //@PreAuthorize("isAuthenticated()")
    public Object todayCloseout(HttpServletRequest request) {
        Long userId = commonController.getUserId(request);
        List<ClosePositionDTO> closePositionOrders = forexClosePositionOrderService.selectTodayList(userId);
        return Response.ok(closePositionOrders);
    }

    /**
     * 今日委托
     *
     * @return
     */
    //@PreAuthorize("isAuthenticated()")
    @GetMapping("/today_entrusts")
    @ApiOperation(value = "今⽇委托", httpMethod = "GET")
    @ResponseBody
    public Object todayEntrustList(HttpServletRequest request) {
        Long userId = commonController.getUserId(request);
        List<ForexEntrustOrderDTO> entrustOrders = entrustOrderService.selectTodayList(userId);
        return Response.ok(entrustOrders);
    }

    /**
     * 今日成交
     *
     * @return
     */
    //@PreAuthorize("isAuthenticated()")
    @GetMapping("/today_turnovers")
    @ApiOperation(value = "今⽇成交", httpMethod = "GET")
    @ResponseBody
    public Object todayTurnoverList(HttpServletRequest request) {
        Long userId = commonController.getUserId(request);
        List<ForexTodayTurnoverDTO> turnoverOrders = turnoverOrderService.selectTodayList(userId);
        return Response.ok(turnoverOrders);
    }

}
